package com.anlu.base.common.security.component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;

import java.util.Objects;

/**
 * OpaqueTokenIntrospector 是 Spring Security 中的一个接口，用于验证和解析不透明令牌（Opaque Tokens）。
 * 不透明令牌是一种令牌类型，其内部结构对于客户端是不可见的，不像 JWT 令牌可以被客户端解析，不透明令牌需要通过向授权服务器的 introspection 端点发送请求来验证和获取其信息
 *
 * OpaqueTokenIntrospector 是在身份验证和授权系统中使用的一个组件，主要用于处理不透明令牌（Opaque Tokens）。
 * 不透明令牌是一种令牌类型，与 JWT（JSON Web Token）不同，它不会直接包含用户信息或权限信息，
 * 而是需要向授权服务器进行验证以获取相应的信息
 */
@Slf4j
@RequiredArgsConstructor
public class PigCustomOpaqueTokenIntrospector implements OpaqueTokenIntrospector {

    private final OAuth2AuthorizationService authorizationService;


    @Override
    public OAuth2AuthenticatedPrincipal introspect(String token) {
        OAuth2Authorization oldAuthorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
        if (Objects.isNull(oldAuthorization)) {
            throw new InvalidBearerTokenException(token);
        }

        //客户端模式默认返回
        if(AuthorizationGrantType.CLIENT_CREDENTIALS.equals(oldAuthorization.getAuthorizationGrantType())){
            return new DefaultOAuth2AuthenticatedPrincipal(oldAuthorization.getPrincipalName(),
                    Objects.requireNonNull(oldAuthorization.getAccessToken().getClaims()),
                    AuthorityUtils.NO_AUTHORITIES);
        }

        return null;
    }
}
